package com.wl.dzt.sys.core.dao.mate;

import com.wl.dzt.sys.annotation.Column;
import com.wl.dzt.sys.annotation.Table;
import com.wl.dzt.sys.annotation.Transient;
import com.wl.dzt.sys.util.DynaBean;
import com.wl.dzt.sys.util.StringUtil;
import com.wl.dzt.sys.util.clazz.ClassUtil;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wl_code@163.com
 * @version 1.0
 * @date 2018/7/5/005
 * @description table 注解处理器
 */
@Component
@Lazy
public class TableHandler {

    /**
     * <b>初始化</b>
     * <p>
     * 遍历所有的类，并且根据注解定义进行解析
     * </p>
     */
    public static void init() {
        ClassUtil.eachClasses("com.wl", clazz -> {
            if (clazz.getAnnotation(Table.class) != null) {
                handler(clazz);
            }
        });
    }


    /**
     * <b>处理@table</b>
     * <p>
     * 填充table对象<br>
     * 填充colunm对象
     * </p>
     *
     * @param clazz
     */
    private static void handler(Class<?> clazz) {
        DataMateTable dataMateTable = new DataMateTable();
        dataMateTable.setTableName(getTableName(clazz));
        dataMateTable.setClazz(clazz);
        dataMateTable.setColumns(getColumns(clazz, dataMateTable.getTableName()));
        DataMateBase.setTable(clazz, dataMateTable);
        DataMateBase.DATA_TABLE_CLASS.put(clazz.getSimpleName(), clazz);
    }

    /**
     * <b> 获取表格名称</b>
     * <p>
     * 根据类名获取所对应的表名称
     * </p>
     *
     * @param clazz
     * @return
     */
    private static String getTableName(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        String defaultName = clazz.getSimpleName(), value = table.value(), tableName = StringUtil.emptyStr(value) ? StringUtil
                .fristLowerCase(defaultName) : value;
        return tableName;
    }

    /**
     * <b>获取数据库字段</b>
     * <p>
     * 根据所对应的类和表名获取 数据库列的源信息
     * </p>
     *
     * @param clazz
     * @param parentTable
     * @return
     */
    private static Map<String, DataMateColumn> getColumns(Class<?> clazz, String parentTable) {
        Map<String, DataMateColumn> map = new HashMap<>();
        Arrays.stream(clazz.getDeclaredFields()).forEach(field -> {
            Map<String, Object> ann = getSimpleField(field);
            if (ann != null) {
                DataMateColumn dataMateColumn = new DataMateColumn();
                dataMateColumn.setText(ann.get("text") + "");
                dataMateColumn.setParentTable(parentTable);// 所属表
                dataMateColumn.setParentClazz(clazz);// 所属类
                String name = field.getName(), tableName = dataMateColumn.getParentTable();
                dataMateColumn.setFieldName(name);// 实体字段名
                dataMateColumn.setColumnName(ann.get("fieldName") + "");// 数据库字段名
                dataMateColumn.setSqlName(tableName + "." + dataMateColumn.getColumnName());// sql字段名
                dataMateColumn.setLazy(new Boolean(ann.get("lazy").toString()));
                Object max = ann.get("maxLength");
                if (max != null)
                    dataMateColumn.setMaxLength(new Integer(ann.get("maxLength").toString()));
                map.put(name, dataMateColumn);
            }
        });
        return map;
    }

    /**
     * <b>根据类的列获取数据库字段名</b>
     * <p>
     * 根据简单名称获取数据库列对象
     * </p>
     *
     * @param field
     * @return
     */
    private static Map<String, Object> getSimpleField(Field field) {
        DynaBean bean = new DynaBean();
        Column column = field.getAnnotation(Column.class);
        String defaultName = field.getName();
        if (column == null) {
            bean.set("fieldName", defaultName);
            bean.set("text", "");
            bean.set("lazy", false);
        } else {
            String value = column.value(), fieldName = StringUtil.emptyStr(value) ? StringUtil.fristLowerCase(defaultName)
                    : value;
            bean.set("fieldName", fieldName);
            bean.set("text", column.text());
            bean.set("maxLength", column.maxLength());
            bean.set("lazy", column.lazy());
        }
        if (field.getAnnotation(Transient.class) != null) {
            return null;
        }
        return bean.getMap();
    }
}
